<script setup>
import { computed, reactive, ref, toRaw, watch } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { InfoFilled } from "@element-plus/icons-vue";

import { getDevices } from "@/api/device";
import { getClients } from "@/api/client";
import { createScript, getScriptDetail, updateScript, testScript } from "@/api/script";
import { ScriptRealTime } from "@/api/ws";
import { deviceArgText, gatewayArgText } from "../utils/default_edit";
import Editor from "./Editor.vue";
import NoRecord from "@/assets/imgs/norecord.png";

const props = defineProps({
  name: {
    type: String,
    default: null
  }
})

const emits = defineEmits(["submit"])

const visible = defineModel("visible")

// 接口基础信息
const defaultData = {
  name: "",
  devices: [],
  mqttClients: [],
  args: 1,
  mode: "polling",
  content: deviceArgText
}
const data = ref({ ...defaultData })
// 定时数据
const defaultInterval = { hour: null, minute: null, second: null }
const defaultTimed = {
  year: null, month: null, day: null, week: null, 
  day_of_week: null, hour: null, minute: null, second: null
}
const intervalData = reactive({ ...defaultInterval })
const timedData = reactive({ ...defaultTimed })

watch(() => data.value.args, val => {
  if (val === 2) {
    data.value.devices = []
    if (data.value.mode === "polling") {
      data.value.mode = "interval"
    }
  }
})

// 获取可选设备列表
const devices = ref([]) 
function toGetDevices() {
  getDevices().then(res => {
    if (res.code === 200) {
      devices.value = res.data
    }
  })
}
toGetDevices()

// 获取可选客户端
const clients = ref([])
function toGetClients() {
  getClients().then(res => {
    if (res.code === 200) {
      clients.value = res.data
    }
  })
}
toGetClients()

// 创建北向接口脚本
function toSubmitScript() {
  let sendData = {...data.value}
  if (data.value.mode === "interval") {
    sendData = {...data.value, ...toRaw(intervalData)}
  } else if (data.value.mode === "advanced") {
    sendData = {...data.value, ...toRaw(timedData)}
  }
  if (props.name) {
    ElMessageBox.confirm("确定修改接口信息吗？", "警告", {
      type: "warning",
      confirmButtonText: "确定",
      cancelButtonText: "取消"
    }).then(() => {
      updateScript(props.name, sendData).then(res => {
        if (res.code === 200) {
          emits("submit")
          ElMessage.success("修改成功")
          visible.value = false
        } else {
          ElMessage.error(res.msg)
        }
      }).catch(err => {
        console.log(err)
        ElMessage.error("网络异常，请稍后重试")
      })
    }).catch(() => {})
  } else {
    createScript(sendData).then(res => {
      if (res.code === 200) {
        ElMessage.success("创建成功")
        visible.value = false
        emits("submit")
      } else {
        ElMessage.error(res.msg)
      }
    }).catch(err => {
      console.log(err)
      ElMessage.error("网络异常，请稍后重试")
    })
  }
}

// 监听传入的脚本名称并拉取详细信息
watch(() => props.name, val => {
  toGetDevices()
  toGetClients()
  if (val) {
    getScriptDetail(val).then(res => {
      if (res.code === 200) {
        data.value = {
          name: res.data.name,
          devices: res.data.devices,
          args: res.data.args,
          mqttClients: res.data.mqttClients,
          mode: res.data.mode,
          content: res.data.content
        }
        if (res.data.mode === "interval") {
            intervalData.hour = res.data.hour
            intervalData.minute = res.data.minute
            intervalData.second = res.data.second
        } else if (res.data.mode === "advanced") {
          timedData.hour = res.data.hour
          timedData.minute = res.data.minute
          timedData.second = res.data.second
          timedData.year = res.data.year
          timedData.month = res.data.month
          timedData.day = res.data.day
          timedData.week = res.data.week
          timedData.day_of_week = res.data.day_of_week
        }
      }
    })
  } else {
    data.value = { ...defaultData }
    Object.assign(intervalData, defaultInterval)
    Object.assign(timedData, defaultTimed)
  }
})

// 脚本测试
const testVisible = ref(false)
const wsConnected = ref(false)
const testData = reactive({
  "device": null,
  "client": "",
})
const testDevices = computed(() => {
  return devices.value.filter(item => data.value.devices.includes(item.no))
})

const wsLoading = ref(false)

const testResult = reactive([])

const sendMsg = () => {
  if (scriptRealTime.connected) {
    scriptRealTime.send("todo")
    setTimeout(sendMsg, 500)
  }
}

const scriptRealTime = ScriptRealTime(
  msg => {
    if (testResult.length > 20) {
      testResult.pop()
    }
    const now = new Date()
    const hour = now.getHours() < 10 ? '0' + now.getHours() : now.getHours()
    const minute = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes()
    const second = now.getSeconds() < 10 ? '0' + now.getSeconds() : now.getSeconds()
    testResult.splice(0, 0, {
      ...msg,
      time: `${hour}:${minute}:${second}`
    })
  },
  () => {
    scriptRealTime.send({
      client: testData.client,
      device: testData.device,
      script: data.value.content
    })
    sendMsg()
    wsLoading.value = false
    wsConnected.value = true
  },
  () => {
    wsLoading.value = false
    wsConnected.value = false
  },
  false
)
function startTest() {
  wsLoading.value = true
  if (scriptRealTime.connected) scriptRealTime.close()
  else scriptRealTime.reconnect()
}

watch(testVisible, val => {
  if (!val) {
    if (scriptRealTime.connected) scriptRealTime.close()
  }
})

watch(() => data.value.args, val => {
  console.log(props.name);
  if (props.name) return
  if (val === 1) {
    data.value.content = deviceArgText
  } else {
    data.value.content = gatewayArgText
  }
}, {
  immediate: true
})
</script>

<template>
  <el-dialog 
    v-model="visible" width="80%"
    :title="props.name ? `${props.name} 详细信息` : '新建北向接口'" 
  >
    <el-form label-width="92px">
      <el-form-item label="接口名称">
        <el-input v-model="data.name" />
      </el-form-item>
      <el-form-item label="参数类型">
        <el-select v-model="data.args">
          <el-option label="单台设备" :value="1" />
          <el-option label="网关信息" :value="2" />
        </el-select>
      </el-form-item>
      <el-form-item v-if="data.args === 1" label="关联设备">
        <el-select 
          v-model="data.devices" 
          multiple collapse-tags collapse-tags-tooltip
        >
          <el-option v-for="dev in devices" :label="`${dev.name}(${dev.no})`" :value="dev.no" />
        </el-select>
      </el-form-item>
      <el-form-item label="输出客户端">
        <el-select 
          v-model="data.mqttClients"
          multiple collapse-tags collapse-tags-tooltip
        >
          <el-option v-for="cli in clients" :label="cli.name" :value="cli.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="采集方式">
        <el-select v-model="data.mode">
          <el-option v-if="data.args === 1" label="轮询触发" value="polling" />
          <el-option label="定时触发" value="interval" />
          <el-option label="高级定时" value="advanced" />
        </el-select>
        <el-tooltip
          v-if="data.mode === 'polling'"
          effect="dark"
          content="轮询触发时请自行指定触发条件，防止大量消息重复发送引起服务器异常！"
          placement="top-start"
        >
          <el-icon style="margin-left: 8px;"><InfoFilled /></el-icon>
        </el-tooltip>
      </el-form-item>
      <el-form-item v-if="data.mode === 'interval'" label="间隔时长">
        <el-input-number class="input-number" v-model="intervalData.hour" :min="0" />
        <span class="char"> 时 </span>
        <el-input-number class="input-number" v-model="intervalData.minute" :min="0" :max="59" />
        <span class="char"> 分 </span>
        <el-input-number class="input-number" v-model="intervalData.second" :min="10" :max="59" />
        <span class="char"> 秒 </span>
      </el-form-item>
      <el-form-item v-else-if="data.mode === 'advanced'" label="触发时间">
        <el-input class="time-input" v-model="timedData.year" />
        <span class="char"> 年 </span>
        <el-input class="time-input" v-model="timedData.month" />
        <span class="char"> 月 </span>
        <el-input class="time-input" v-model="timedData.day" />
        <span class="char"> 日 </span>
        <el-input class="time-input" v-model="timedData.week" />
        <span class="char"> 周 </span>
        <span class="char"> 星期 </span>
        <el-input class="time-input" style="margin-right: 8px;" v-model="timedData.day_of_week" />
        <el-input class="time-input" v-model="timedData.hour" />
        <span class="char"> 时 </span>
        <el-input class="time-input" v-model="timedData.minute" />
        <span class="char"> 分 </span>
        <el-input class="time-input" v-model="timedData.second" />
        <span class="char"> 秒 </span>
        <span class="char"> 起始时间 </span>
        <el-input class="input-number2" v-model="timedData.start_date" />
        <span class="char"> 结束时间 </span>
        <el-input class="input-number2" v-model="timedData.end_date" />
      </el-form-item>
      <el-form-item label="作业脚本">
        <Editor :devices="data.devices" v-model="data.content" />
      </el-form-item>
    </el-form>
    <div class="btn-group">
      <el-button type="primary" text @click="testVisible = true">运行测试</el-button>
      <el-button type="primary" @click="toSubmitScript">
        {{ props.name ? '修 改' : '创 建' }}
      </el-button>
      <el-button>取 消</el-button>
    </div>
  </el-dialog>
  <el-dialog v-model="testVisible" draggable title="脚本可行性测试">
    <el-form label-position="top">
      <el-form-item label="测试设备">
        <el-select v-model="testData.device" :disabled="wsConnected || wsLoading">
          <el-option v-for="dev in testDevices" :label="`${dev.name}(${dev.no})`" :value="dev.no" />
        </el-select>
      </el-form-item>
      <el-form-item label="输出方式/客户端">
        <el-select v-model="testData.client" :disabled="wsConnected || wsLoading">
          <el-option label="消息窗口输出" value="" />
          <el-option v-for="cli in data.mqttClients" :label="cli" :value="cli" />
        </el-select>
      </el-form-item>
      <el-form-item label="消息窗口">
        <el-scrollbar class="test-scrollbar" height="480px">
          <el-empty 
            v-if="testResult.length <= 0" style="margin: auto;" 
            description="暂无返回结果" 
            :image="NoRecord"
          />
          <div v-else>
            <el-card shadow="hover" class="test-result-card" v-for="item in testResult">
              <span :class="item.code === 200 ? 'test-success' : 'test-error'">
                {{ item.code === 200 ? '执行成功' : '执行失败' }}：{{ item.msg }}
              </span>
              <div class="test-time">{{ item.time }}</div>
            </el-card>
          </div>
        </el-scrollbar>
      </el-form-item>
      <el-form-item>
        <div class="test-btn-group">
          <el-button 
            :loading="wsLoading" 
            :type="wsConnected ? 'danger' : 'primary'" 
            @click="startTest"
          >{{ wsConnected ? "停 止" : "运 行" }}</el-button>
          <el-button v-show="testResult.length > 0" @click="testResult.length = 0">清空消息窗口</el-button>
        </div>
      </el-form-item>
    </el-form>
  </el-dialog>
</template>

<style lang="scss" scoped>
.btn-group {
  display: flex;
  margin-top: 12px;
  justify-content: flex-end;
}
.char {
  margin: 0 8px;
}
.time-input {
  width: 72px;
  margin-bottom: 8px;
}
.input-number {
  width: 108px;
  margin-bottom: 8px;
}
.input-number2 {
  width: 156px;
  margin-bottom: 8px;
}
.test-scrollbar {
  width: 100%;
  box-sizing: border-box;
  padding: 12px;
  border: 2px solid #eee;
  box-shadow: 1px 1px 1px #eee;
  background-color: #f6f6f6;
}
.test-time {
  color: #aaa;
  font-size: 12px;
  height: 16px;
  line-height: 16px;
}
.test-result-card {
  margin-bottom: 8px;
  :deep(.el-card__body) {
    padding: 8px 12px;
  }
}
.test-success {
  color: var(--el-color-success);
}
.test-error {
  color: var(--el-color-error);
}
.test-btn-group {
  width: 100%;
  display: flex;
  justify-content: center;
}
</style>
